/**
 * Layui 数字输入组件
 *
 * @author  iTanken
 * @since   2019-03-29
 * @version 2020-01-19：数字键盘纵向定位自适应
 * @version 2020-04-02：添加功能按钮悬浮提示开关参数；添加悬浮提示内部键盘按钮样式；修复 number 类型输入框小数输入问题
 * @modify by imlzw imlzw@vip.qq.com 2020-10-17
 * @platform http://adai.imlzw.cn
 */
layui.define(['jquery'], function (exports) {
    var $ = layui.$, baseClassName = 'layui-input-number', keyClassName = 'layui-keyboard-number',
        style = ['<style type="text/css">',
            '.', baseClassName, ' + .', keyClassName, ' { position: fixed; display: block; ',
            ' background-color: #f2f2f2; border-radius: 2px; border: 1px solid #e6e6e6; outline: none; }',
            '.', keyClassName, ' .layui-key-btn { font-family: Consolas; font-size: 17px; font-weight: 600; ',
            ' text-align: center; background-color: #ffffff; cursor: pointer; overflow: hidden; padding: 0px; line-height: 42px;height: 42px; }',
            '.', keyClassName, ' .layui-key-btn:active { background-color: #f2f2f2; }',
            '.layui-layer-tips kbd { display: inline-block; padding: 3px 5px; font-size: 11px;',
            ' line-height: 10px; color: #24292e; vertical-align: middle; background-color: #fafbfc;',
            ' border: 1px solid #d1d5da; border-radius: 3px; box-shadow: inset 0 -1px 0 #d1d5da; }',
            `
            .layui-keyboard-number .layui-row .layui-col-xs3 {
                height: 43px;
            }
            `,
            '</style>'].join('');

    $('head link:last')[0] && $('head link:last').after(style) || $('head').append(style);


    let Number = function () {
        this.v = '1.0.0';
        this.renderIns = {};
    }

    /**
     * 渲染组件
     * @param options
     */
    Number.prototype.render = function (options) {
        var numberInput = {
            /** 默认配置选项 */
            options: {
                // 组件渲染编号
                id: options.id,
                // 自定义选择器
                // 123：123键置顶, 789：789键置顶
                topBtns: 123,
                // 右侧功能按钮
                rightBtns: true,
                // 功能按钮提示
                showTips: true,
                // 监听键盘事件
                listening: true,
                // 配置默认小数精确度，-1 不处理精确度
                defaultPrec: -1,
                // 初始化回调，无参
                initEnd: $.noop,
                // 触发显示回调，参数为当前输入框和数字键盘的 jQuery 对象
                showEnd: $.noop,
                // 隐藏键盘回调，参数为当前输入框的 jQuery 对象
                hideEnd: $.noop,
                // z-index
                zIndex: 10000000000
            },
            /** 初始化 */
            init: function (custom) {
                var _this = this;
                _this.options = $.extend(_this.options, custom);
                $('#' + _this.options.id).attr({
                    "readonly": "readonly"
                }).on('focus', function (e) {
                    _this.showKeyboard(_this, $(this));
                });
                typeof _this.options.initEnd === 'function' && _this.options.initEnd();
            },
            /** 获取按键悬浮提示 */
            getTips: function (tip) {
                return this.options.showTips ? (' lay-tips="' + tip + '"') : '';
            },
            /** 显示数字键盘 */
            showKeyboard: function (_this, $input) {
                // 2020-04-02：修复小数输入问题，将 number 类型输入框一律设置为 text
                $input.prop('type') === 'number' && $input.attr('type', 'text');
                var $keyBoard = $input.next('.' + keyClassName);
                if (!$keyBoard[0]) {
                    // 不存在，添加元素
                    var sizeXS = _this.options.rightBtns ? 'xs3' : 'xs4',
                        sizeZero = _this.options.rightBtns ? 'xs6' : 'xs4',
                        // 按钮 123
                        btn123 = [
                            '<div class="layui-col-', sizeXS, '">',
                            '<div class="layui-card">',
                            '<div class="layui-key-btn" data-keycode="49 97">1</div>',
                            '</div>',
                            '</div>',
                            '<div class="layui-col-', sizeXS, '">',
                            '<div class="layui-card">',
                            '<div class="layui-key-btn" data-keycode="50 98">2</div>',
                            '</div>',
                            '</div>',
                            '<div class="layui-col-', sizeXS, '">',
                            '<div class="layui-card">',
                            '<div class="layui-key-btn" data-keycode="51 99">3</div>',
                            '</div>',
                            '</div>'
                        ].join(''),
                        // 按钮 789
                        btn789 = [
                            '<div class="layui-col-', sizeXS, '">',
                            '<div class="layui-card">',
                            '<div class="layui-key-btn" data-keycode="55 103">7</div>',
                            '</div>',
                            '</div>',
                            '<div class="layui-col-', sizeXS, '">',
                            '<div class="layui-card">',
                            '<div class="layui-key-btn" data-keycode="56 104">8</div>',
                            '</div>',
                            '</div>',
                            '<div class="layui-col-', sizeXS, '">',
                            '<div class="layui-card">',
                            '<div class="layui-key-btn" data-keycode="57 105">9</div>',
                            '</div>',
                            '</div>'
                        ].join(''),
                        /* 退格键 */
                        backspace = [
                            '<div class="layui-col-', sizeXS, '">',
                            '<div class="layui-card">',
                            '<div class="layui-key-btn" data-keycode="8">',
                            '<i class="layui-icon layui-icon-return"', _this.getTips('退格 <kbd>Backspace</kbd>'), '></i>',
                            '</div>',
                            '</div>',
                            '</div>'
                        ].join(''),
                        /* 增加键 */
                        add = [
                            '<div class="layui-col-', sizeXS, '">',
                            '<div class="layui-card">',
                            '<div class="layui-key-btn" data-keycode="38 39">',
                            '<i class="layui-icon layui-icon-up"', _this.getTips('增加 <kbd>↑</kbd>'), '></i>',
                            '</div>',
                            '</div>',
                            '</div>'
                        ].join(''),
                        /* 减小键 */
                        reduce = [
                            '<div class="layui-col-', sizeXS, '">',
                            '<div class="layui-card">',
                            '<div class="layui-key-btn" data-keycode="37 40">',
                            '<i class="layui-icon layui-icon-down"', _this.getTips('减小 <kbd>↓</kbd>'), '></i>',
                            '</div>',
                            '</div>',
                            '</div>'
                        ].join(''),
                        /* 清空键 */
                        reset = [
                            '<div class="layui-col-', sizeXS, '">',
                            '<div class="layui-card">',
                            '<div class="layui-key-btn" data-keycode="46">',
                            '<i class="layui-icon layui-icon-refresh-1"', _this.getTips('清空 <kbd>Delete</kbd>'), '></i>',
                            '</div>',
                            '</div>',
                            '</div>'
                        ].join('');
                    let showWidth = $input.width() + 10;
                    showWidth = showWidth > 170 ? 170 : showWidth;
                    $input.after(['<div tabindex="0" hidefocus="true" class="', keyClassName,
                        ' layui-unselect layui-anim layui-anim-upbit" ',
                        'style="visibility:hidden;width:', $input.width() + 10, 'px;">',
                        '<div class="layui-row layui-col-space1">',
                        _this.options.topBtns == 789 ? btn789 : btn123,
                        _this.options.rightBtns ? backspace : '',
                        '<div class="layui-col-', sizeXS, '">',
                        '<div class="layui-card">',
                        '<div class="layui-key-btn" data-keycode="52 100">4</div>',
                        '</div>',
                        '</div>',
                        '<div class="layui-col-', sizeXS, '">',
                        '<div class="layui-card">',
                        '<div class="layui-key-btn" data-keycode="53 101">5</div>',
                        '</div>',
                        '</div>',
                        '<div class="layui-col-', sizeXS, '">',
                        '<div class="layui-card">',
                        '<div class="layui-key-btn" data-keycode="54 102">6</div>',
                        '</div>',
                        '</div>',
                        _this.options.rightBtns ? add : '',
                        _this.options.topBtns == 789 ? btn123 : btn789,
                        _this.options.rightBtns ? reduce : '',
                        _this.options.rightBtns ? '' : backspace,
                        '<div class="layui-col-', sizeZero, '">',
                        '<div class="layui-card">',
                        '<div class="layui-key-btn" data-keycode="48 96">0</div>',
                        '</div>',
                        '</div>',
                        '<div class="layui-col-', sizeXS, '">',
                        '<div class="layui-card">',
                        '<div class="layui-key-btn" data-keycode="110 190">.</div>',
                        '</div>',
                        '</div>',
                        _this.options.rightBtns ? reset : '',
                        '</div>',
                        '</div>'].join(''));

                    $keyBoard = $input.next('.' + keyClassName);

                    $keyBoard.on('touchstart click', '.layui-key-btn', function (e) {
                        _this.setValue(_this, $input, $(this));
                        layui.stope(e);
                        return false;
                    });
                    $keyBoard.on('blur', function (e) {
                        _this.setValueRange(_this, $input, _this.toFixedPrec(_this, $input));
                        $keyBoard.remove(); // $keyBoard.hide();
                        typeof _this.options.hideEnd === 'function' && _this.options.hideEnd($input);
                    });
                    _this.options.listening && _this.initKeyListening(_this, $input, $keyBoard);
                }

                _this.display(_this, $input, $keyBoard);
            },
            /** 设置数字键盘样式并显示 */
            display: function (_this, $input, $keyBoard) {
                let rect = $input[0].getBoundingClientRect();
                let dropRect = $keyBoard[0].getBoundingClientRect();
                let y = rect.y || rect.top || 0;
                let clientHeight = document.documentElement.clientHeight;
                let downHeight = clientHeight - y - rect.height - 4;
                let upHeight = rect.top - 4;
                let top = y;
                if (dropRect.height <= downHeight) {
                    top = rect.top + rect.height + 4;
                } else if (dropRect.height <= upHeight) {
                    top = rect.top - dropRect.height - 4;
                } else{
                    top = rect.top + rect.height + 4;
                }

                $keyBoard.css({
                    'top': top + 'px',
                    'left': rect.x + 'px',
                    'width': rect.width - 2 + 'px',
                    'visibility': '',
                    'z-index': _this.options.zIndex
                });

                $keyBoard.show(200, function () {
                    typeof _this.options.showEnd === 'function' && _this.options.showEnd($input, $keyBoard);
                }).focus();
            },
            /** 初始化键盘监听事件 */
            initKeyListening: function (_this, $input, $keyBoard) {
                var $key, code;
                $keyBoard.on('keydown', function (e) {
                    code = e.keyCode;
                    var inputNumber = parseInt($input.val(), 10) || 0;
                    if (code === 107 || e.shiftKey && code === 187) {
                        // 加号切换正数
                        inputNumber < 0 && _this.setValueRange(_this, $input, Math.abs(inputNumber));
                    } else if (code === 109 || e.shiftKey && code === 189) {
                        // 减号切换负数
                        inputNumber > 0 && _this.setValueRange(_this, $input, '-' + inputNumber);
                    } else {
                        // 监听数字键盘，退格键(Backspace)/重置键(Delete)
                        $key = $keyBoard.find('.layui-key-btn[data-keycode~=' + code + ']');
                        if ($key[0]) {
                            $key.trigger('click').css("background-color", "#f2f2f2");
                            $keyBoard.off('keyup').on('keyup', function (e) {
                                $('.layui-key-btn[data-keycode]').css("background-color", "#ffffff");
                            });
                        }
                        if (code > 36 && code < 41) {
                            // 上下左右键，防止触发混动条滑动事件
                            return false;
                        }
                    }
                    return true;
                });
            },
            /** 处理精确度 */
            toFixedPrec: function (_this, $input, val1, val2) {
                var m, s, rs, prec = $.trim($input.data('prec'));
                // 2020-04-02：修复获取小数精确度配置值问题
                prec = parseInt(prec === '' || isNaN(prec) ? _this.options.defaultPrec : prec, 10);

                val1 = val1 === undefined ? $input.val() : val1;
                val1 = val1 == '' ? ($input.attr('min') || 0) : val1;
                rs = val1.toString().split('.')[1];
                if (prec < 0) {
                    prec = rs && rs.length || prec;
                }

                val2 = val2 || 0;
                rs = val2.toString().split('.')[1];
                prec = Math.max(prec, rs ? rs.length : 0);

                m = Math.pow(10, prec);
                s = ((val1 * m + val2 * m).toFixed(0) / m).toString();
                rs = s.indexOf('.');
                if (rs < 0 && prec > 0) {
                    rs = s.length;
                    s += '.';
                }
                while (s.length <= rs + prec) {
                    s += '0';
                }
                return s;
            },
            /** 设置值范围 */
            setValueRange: function (_this, $input, value) {
                var minVal = $input.attr('min') || Math.pow(-2, 63),
                    maxVal = $input.attr('max') || Math.pow(2, 63) - 1;

                minVal = typeof minVal === 'string' && minVal.indexOf('.') > -1 ? parseFloat(minVal) : parseInt(minVal, 10);
                maxVal = typeof maxVal === 'string' && maxVal.indexOf('.') > -1 ? parseFloat(maxVal) : parseInt(maxVal, 10);

                if (value < minVal) {
                    value = _this.toFixedPrec(_this, $input, minVal);
                    _this.tips($input, '最小值为 <kbd>' + minVal + '</kbd>！');
                }
                if (value > maxVal) {
                    value = _this.toFixedPrec(_this, $input, maxVal);
                    _this.tips($input, '最大值为 <kbd>' + maxVal + '</kbd>！');
                }
                value = value < minVal ? minVal : (value > maxVal ? maxVal : value);

                $input.val(value);
            },
            /** 设置输入框值 */
            setValue: function (_this, $input, $key) {
                var inputVal = $.trim($input.val()), keyVal = $.trim($key.text()), changeVal,
                    prec = $.trim($input.data('prec')), isDecimal = inputVal.indexOf('.') > -1;
                // 2020-04-02：修复获取小数精确度配置值问题
                prec = parseInt(prec === '' || isNaN(prec) ? _this.options.defaultPrec : prec, 10);

                if ($.inArray(keyVal, ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.']) > -1) {
                    if (keyVal === '.') {
                        if (inputVal === '' || isDecimal) {
                            return;
                        }
                        if (prec === 0) {
                            _this.tips($input, '当前字段不允许输入小数！');
                            return;
                        }
                    }
                    if (keyVal === '0' && inputVal.indexOf('0') === 0 && !isDecimal) {
                        return;
                    }
                    if (inputVal.indexOf('.') > -1 && inputVal.split('.')[1].length >= prec && prec > 0) {
                        _this.tips($input, '精确度为保留小数点后 <kbd>' + prec + '</kbd> 位！');
                        return;
                    }

                    changeVal = inputVal = (keyVal !== '.' && inputVal === '0' ? '' : inputVal) + keyVal;
                    $input.val(inputVal);
                } else {
                    changeVal = inputVal === '' ? 0 : inputVal,
                        step = $input.attr('step');
                    if (isDecimal) {
                        step = parseFloat(step) || 0.1;
                        changeVal = parseFloat(changeVal);
                    } else {
                        step = parseInt(step, 10) || 1;
                        changeVal = parseInt(changeVal, 10);
                    }
                    // right function buttons
                    switch ($key.data('keycode')) {
                        case '38 39':
                            // ↑、→ 键增加
                            changeVal = _this.toFixedPrec(_this, $input, changeVal, step);
                            break;
                        case '37 40':
                            // ↓、← 键减小
                            changeVal = _this.toFixedPrec(_this, $input, changeVal, -step);
                            break;
                        case 8:
                            // Backspace 键退格
                            var valLength = inputVal.length;
                            valLength && $input.val(inputVal.substring(0, valLength - 1));
                            return;
                        case 46:
                            // Delete 键清空
                            $input.val('');
                            return;
                    }
                }
                $input.val(changeVal);
            },
            /** 提示 */
            tips: function ($input, msg) {
                return layer.tips(msg, $input, {tips: [1, '#01AAED'], time: 2e3, anim: 6, zIndex: this.options.zIndex});
            }
        };
        this.renderIns[options.id] = numberInput;
        numberInput.init(options);
        return numberInput;
    }

    /**
     * 获取或者更新组件数据
     * @param id
     * @param typeOrVals
     * @param isAppend
     */
    Number.prototype.value = function (id, typeOrVals, isAppend) {

    }
    exports('number', new Number());
});
